use crate::config::create_data_item_service;
use crate::global_var::GLOBAL_QUEUE;
use crate::models::DataItem;
use crate::service::data_item_service;
use crate::utils::{Client, Message};
use pyo3::prelude::*;
use pyo3::types::PyTuple;
use serde_json::json;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::Mutex;
use tokio::sync::Semaphore;

#[tauri::command]
pub async fn run_playwright(url_list: Vec<String>) {
    let max_concurrency = 10;
    let semaphore = Arc::new(Semaphore::new(max_concurrency));

    let counter = Arc::new(Mutex::new(0));
    let total_threads = url_list.len();

    for url in url_list {
        let counter = Arc::clone(&counter);
        let semaphore = Arc::clone(&semaphore);
        tokio::spawn(async move {
            let _permit = semaphore.acquire().await.unwrap();
            let data_item_service = create_data_item_service();
            let result = Python::with_gil(|py| -> Result<HashMap<String, String>, PyErr> {
                let lib = py.import("lib")?;
                let args = PyTuple::new(py, &[url.to_string()])?;
                let result: HashMap<String, String> =
                    lib.call_method("run", args, None)?.extract()?;
                Ok(result)
            });
            let client = Client::new(GLOBAL_QUEUE.clone());
            match result {
                Ok(data) => {
                    client.send(Message::Data(data.clone()));
                    let data_item = DataItem {
                        id: None,
                        name: "Playwright".to_string(),
                        value: json!(data),
                        created_at: None,
                        updated_at: None,
                    };
                    data_item_service.insert_data_item(&data_item).unwrap();
                    println!("Client: Sent Data message: {:?}", data);
                }
                Err(err) => {
                    println!("Python error: {:?}", err);
                    client.send(Message::Data(HashMap::from([
                        ("status".to_string(), "error".to_string()),
                        ("data".to_string(), err.to_string()),
                    ])));
                }
            }

            let mut count = counter.lock().await;
            *count += 1;

            if *count == total_threads {
                let mut stop_task = HashMap::new();
                stop_task.insert(String::from("data"), String::from("finished"));
                stop_task.insert(String::from("status"), String::from("stop"));
                client.send(Message::Data(stop_task));
                println!("All threads completed. Sent completion event.");
            }
        });
    }
}
